# 先请求验证码
import json
import pickle
import sys
import threading
import time
from ctypes import *

import facade
import requests
from xjlibrary.mdatetime.mtime import MDateTime
from xjlibrary.mprocesspoll.MThreadingRun import MThreadingRun
from xjlibrary.our_file_dir import BaseDir

curPath = BaseDir.get_file_dir_absolute(__file__)
sys.path.append(curPath)

from base_sipo import BaseSipo

curPath = BaseDir.get_file_dir_absolute(__file__)
configfile = BaseDir.get_new_path(curPath, "db.ini")
jpgdir = BaseDir.get_new_path(curPath, "jpg")
BaseDir.create_dir(jpgdir)


class DiscernCode(object):
    """
    将识别验证码封装成一个类
    """

    def __init__(self, logger):
        self.appId = 6249  # 软件ＩＤ，开发者分成必要参数。登录开发者后台【我的软件】获得！
        self.appKey = b'439aa4305465df04545dad067bb31751'  # 软件密钥，开发者分成必要参数。登录开发者后台【我的软件】获得！
        self.YDMApi = windll.LoadLibrary('yundamaAPI-x64')
        # 注意这里是普通会员账号，不是开发者账号，注册地址 http://www.yundama.com/index/reg/user
        # 开发者可以联系客服领取免费调试题分
        # self.username = b'xujiang'
        # self.password = b'xujiang1994323'
        self.username = b'office'
        self.password = b'officeHelper$123'
        # 例：1004表示4位字母数字，不同类型收费不同。请准确填写，否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html
        self.codetype = 6300
        # 分配30个字节存放识别结果
        self.result = c_char_p(b"                              ")
        # 验证码文件路径
        # self.filename = jpgpath.encode('utf-8')
        self.logger = logger
        # 识别超时时间 单位：秒
        self.timeout = 60

    def easy_decode_by_path(self, jpgpath):
        self.logger.info("正在开始一键识别{}".format(jpgpath))
        # 一键识别函数，无需调用 YDM_SetAppInfo 和 YDM_Login，适合脚本调用
        captchaId = self.YDMApi.YDM_EasyDecodeByPath(self.username,
                                                     self.password,
                                                     self.appId,
                                                     self.appKey,
                                                     jpgpath,
                                                     self.codetype,
                                                     self.timeout,
                                                     self.result)

        self.logger.info("一键识别：验证码ID：%d，识别结果：%s" % (captchaId, self.result.value))
        if int(captchaId) > 0:
            return True, str(self.result.value)
        else:
            self.logger.error("识别失败 请检查原因")
            return False, ""


class sipogovLogin(BaseSipo):

    def __init__(self):
        self.filelogger = facade.get_timerotatingfilelogger(BaseDir.get_new_path(curPath, "logs", "step1_check"))
        super().__init__(self.filelogger)
        self.configfile = configfile

    def discern_code(self, jpgpath):
        """
        识别验证码通过云打码
        :return:
        """
        boolresult, code = DiscernCode(self.logger).easy_decode_by_path(jpgpath)
        if boolresult:
            code = code.replace("b'", "").replace("'", "")
            return True, code
        else:
            return False, ""

    def set_logger(self, logger):
        self.logger = logger

    def proxy_clear(self, source):
        """
        查看哪些代理没有cookie 将状态设置为0
        :return:
        """
        inputobj1 = set()
        inputobj2 = set()
        sql = "select `proxy`,`ipaddr` from proxy_pool where stat > -1 and `source`='{}'".format(source)
        rows = self.mysqlutils.SelectFromDB(sql)
        for row in rows:
            inputobj1.add(row[1])
        rows = self.db.cookies.find(
            {"source": source, "stat": {"$in": [0, 1]}, "origin": "http://pss-system.cnipa.gov.cn"},
            {"proxy": 1, "ip": 1})
        for row in rows:
            inputobj2.add(row["ip"])
        inputobj3 = inputobj1 - inputobj2
        if len(inputobj2) == 1:
            inputobj2.add("test")
        if inputobj2:
            sql = "update proxy_pool set stat=1 where `source`='{}' and `ipaddr` in {} and stat != -1".format(source,
                                                                                                              tuple(
                                                                                                                  inputobj2))
            self.mysqlutils.ExeSqlToDB(sql)
        if inputobj3:
            if len(inputobj3) == 1:
                inputobj3.add("test")
            sql = "update proxy_pool set stat=0 where `source`='{}' and stat >-1 and `ipaddr` in {}".format(source,
                                                                                                            tuple(
                                                                                                                inputobj3))
            self.mysqlutils.ExeSqlToDB(sql)
        else:
            time.sleep(20)

    def get_proxy_ip(self):
        """
        获取快代理ip
        :return:
        """
        url = "http://dps.kdlapi.com/api/getdps/?orderid=925226808001745&num=50&area=%E5%9B%BD%E5%86%85&pt=1&ut=2&format=json&sep=1"
        BoolResult, errString, r = facade.BaseRequest(url, endstring="")
        if BoolResult:
            dicts = json.loads(r.text)
            listvalues = []
            proxy_list = dicts["data"]["proxy_list"]
            for proxy in proxy_list:
                ip = proxy.split(":")[0]
                listvalues.append((ip, proxy))
            if listvalues:
                sql = "replace into `proxy_pool`(`ipaddr`,`proxy`,`stat`,`source`) values(%s,%s,0,'kuaidaili')"
                self.mysqlutils.ExeSqlMany(sql, listvalues)
        else:
            self.logger.info("提取ip失败")

    def get_proxy_ip_2(self):
        """
        获取米朴代理
        :return:
        """
        url = "https://proxyapi.mimvp.com/api/fetchsecret.php?orderid=868476304950104401&num=75&time_avail=10&http_type=3&result_fields=1,3&result_format=json"
        BoolResult, errString, r = facade.BaseRequest(url, endstring="")
        if BoolResult:
            dicts = json.loads(r.text)
            listvalues = []
            proxy_list = dicts["result"]
            for proxyobj in proxy_list:
                proxy = proxyobj["ip:port"]
                ip = proxy.split(":")[0]
                interval = proxyobj["time_interval"]
                listvalues.append((ip, proxy, int(interval)))
            if listvalues:
                sql = "replace into `proxy_pool`(`ipaddr`,`proxy`,`stat`,`source`,`interval`) values(%s,%s,0,'mimvp',%s)"
                self.mysqlutils.ExeSqlMany(sql, listvalues)
        else:
            self.logger.info("提取ip失败")

    def get_proxy_ip_3(self):
        """
        获取芝麻代理
        :return:
        """
        url = "http://webapi.http.zhimacangku.com/getip?num=50&type=2&pro=&city=0&yys=0&port=1&time=3&ts=1&ys=0&cs=0&lb=1&sb=0&pb=45&mr=2&regions="
        BoolResult, errString, r = facade.BaseRequest(url, endstring="")
        if BoolResult:
            dicts = json.loads(r.text)
            listvalues = []
            proxy_list = dicts["data"]
            for proxyobj in proxy_list:
                ip = proxyobj["ip"]
                port = proxyobj["port"]
                expire_time = proxyobj["expire_time"]
                expire_time = expire_time.replace(":", "").replace(" ", "").replace("-", "")
                proxy = str(ip) + ":" + str(port)
                listvalues.append((ip, proxy, int(expire_time)))
            if listvalues:
                sql = "replace into `proxy_pool`(`ipaddr`,`proxy`,`stat`,`source`,`interval`) values(%s,%s,0,'zhima',%s)"
                self.mysqlutils.ExeSqlMany(sql, listvalues)
        else:
            self.logger.info("提取ip失败")


class ThreadRun(MThreadingRun):
    def __init__(self, num):
        self.localVal = threading.local()
        self.down = sipogovLogin()
        self.down.set_localVal(self.localVal)
        super(ThreadRun, self).__init__(num, self.down.filelogger)
        self.logger = self.down.filelogger

    def getTask(self, *args, **kwargs):
        """
        :param args:
        :param kwargs:
        :return:
        """
        """
        sysstr = platform.system()
        if sysstr == "Windows":
            ip = GetLocalIPByPrefix("192.168.")
        else:
            ip = get_local_ip("enp2s0")
        if ip == "192.168.30.179":
            source = "mimvp"
            self.down.get_proxy_ip_2()
            self.down.proxy_clear(source)
        else:
            source = "kuaidaili"
            self.down.get_proxy_ip()
            self.down.proxy_clear(source)
        """
        # self.down.get_proxy_ip_3()
        # sys.exit(-1)
        usersetstat = MDateTime.get_now_datetime(format="%H%M%S", struct_time=time.localtime(time.time()))
        if usersetstat < "001500":
            sql = "update `user` set stat=1,isajxcount=0 where stat != -1"
            self.down.mysqlutils.ExeSqlToDB(sql)
        ip = "192.168.30.179"
        source = "mimvp"
        self.down.get_proxy_ip_2()
        self.down.proxy_clear(source)
        # source = "school"
        # print(ip)
        print(source)
        time.sleep(10)

        if self.thread_pool.work_queue_is_empty():
            sql = "SELECT `proxy`,`source` FROM `proxy_pool` WHERE stat=0 and `source`='{}' ORDER BY create_time ASC".format(
                source)
            rows = self.down.mysqlutils.SelectFromDB(sql)

            sql = "SELECT `proxy`,`source` FROM `proxy_pool` WHERE stat in (1,-2) and `source`='{}' ORDER BY create_time ASC".format(
                source)
            rows1 = self.down.mysqlutils.SelectFromDB(sql)
            # for row in rows:
            #     sql = "update `proxy_pool` set stat=2 where `proxy`='{}';".format(row[0])
            #     self.down.mysqlutils.SelectFromDB(sql)
            if rows:
                return (1, rows, rows1)
            else:
                self.logger.info("没有状态为0的代理")
                return (0, "", "")
        else:
            # self.logger.info("任务队列不为空")
            return (0, "", "")

    def setTask(self, results=None, *args, **kwargs):
        num, rows, rows1 = results
        if num == 0:
            return True
        for row in rows:
            self.add_job(self.func, (num, row), *args, **kwargs)
        for row in rows1:
            self.add_job(self.func, (num, row), *args, **kwargs)

        for i in range(24):
            self.logger.info("sleep time {} s".format(str((i + 1) * 5)))
            time.sleep(5)

    def fun(self, threadval, *args, **kwargs):
        rowtuple = args[0]
        num, rowmysql = rowtuple
        self.logger.info("num is {} ".format(num))
        if num == 1:
            self.down.set_proxys(rowmysql[0], rowmysql[1])
            self.down.set_ipaddr(self.down.localVal.proxys)
            # 开始检查代理有效性
            # boolpost = self.down.check_proxy_post(self.down.localVal.proxys)
            # if not boolpost:
            #     sql = "update proxy_pool set stat=-5 where `proxy` = '{}' and `source`='{}'".format(rowmysql[0],
            #                                                                                         rowmysql[1])
            #     threadval.result_queue.put(sql)
            #     return True
            msg = self.down.check_proxys_is_used(self.down.localVal.proxys)
            if msg == "IP":
                sql = "update proxy_pool set stat=-2 where `proxy` = '{}' and `source`='{}'".format(rowmysql[0],
                                                                                                    rowmysql[1])
                threadval.result_queue.put(sql)
                return True
            if not msg:
                self.logger.info("代理失效")
                sql = "update proxy_pool set stat=-1 where `proxy` = '{}' and `source`='{}'".format(rowmysql[0],
                                                                                                    rowmysql[1])
                threadval.result_queue.put(sql)
                return True
            # 代表新的代理需要设置cookie,检查cookies是否已经存在
            rows = self.down.db.cookies.find({"ip": self.down.localVal.ipaddr, "source": rowmysql[1], "stat": -1,
                                              "origin": "http://pss-system.cnipa.gov.cn"})
            for row in rows:
                # 设置为通过验证的代理 防止cookie里代理端口不能用
                proxy = rowmysql[0]  # row["proxy"]
                bytess = row["cookie"]
                cookie = pickle.loads(bytess)
                self.down.set_proxys(proxy, rowmysql[1])
                self.down.set_ipaddr(self.down.localVal.proxys)
                self.down.localVal.cooke = cookie

                rbool, msg = self.down.is_login_and_ip(requests.session(), self.down.localVal.proxys, cookie)

                if rbool:
                    self.logger.info("检查到存在的cookie有效,-1状态将写0{}".format(row["proxy"]))
                    # 状态为没使用状态，其他状态维持
                    self.down.db.cookies.update({"_id": row["_id"]},
                                                {"$set": {"stat": 0, "proxy": proxy,
                                                          "updatetime": MDateTime.get_now_datetime(
                                                              struct_time=time.localtime(time.time()))}})
                    sql = "update proxy_pool set stat=1 where `ipaddr` = '{}' and `source`='{}' and `stat` != -1".format(
                        self.down.localVal.ipaddr,
                        rowmysql[1])
                    threadval.result_queue.put(sql)
                    break
                else:
                    self.logger.info("检查到存在的cookie无效,如果是登陆失败状态将写-2{}".format(row["proxy"]))
                    # 如果登陆失败
                    if msg == "登陆失败":
                        self.logger.info("检查到cookie状态登陆失败写-3{}".format(row["proxy"]))
                        # 代表代理没问题 只是cookies永久失效
                        self.down.db.cookies.update({"_id": row["_id"]},
                                                    {"$set": {"stat": -3,
                                                              "updatetime": MDateTime.get_now_datetime(
                                                                  struct_time=time.localtime(time.time()))}})

            rows = self.down.db.cookies.find({"proxy": rowmysql[0], "source": rowmysql[1], "stat": {"$in": [0, -1, 1]},
                                              "origin": "http://pss-system.cnipa.gov.cn"})
            if rows.count() == 0:
                sql = "update `proxy_pool` set stat=2 where `proxy` = '{}' and `source`='{}'".format(rowmysql[0],
                                                                                                     rowmysql[1])
                threadval.result_queue.put(sql)

    def thread_pool_hook(self, thread_pool_dicts, thread, args, kwargs) -> dict:
        return {}

    def dealresult(self, *args, **kwargs):
        self.logger.info("进入dealresult")
        for result in self.results:
            self.logger.info("result is {}".format(result))
            self.logger.info(self.down.mysqlutils)
            self.down.mysqlutils.ExeSqlToDB(result)
        self.logger.info("dealresult 结束")
        time.sleep(5)

    # 上层重写的方法必须调用该方法
    def setProxy(self, proxysList=None):
        time.sleep(120)


if __name__ == "__main__":
    down = ThreadRun(10)
    down.thread_pool.set_work_queue(3)
    down.run()
